package com.ganjiangps;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.IService;
import com.ganjiangps.huochetou.common.BaseController;
import com.ganjiangps.huochetou.common.constant.Constant;
import com.ganjiangps.huochetou.common.constant.Result_Constant;
import com.ganjiangps.huochetou.common.util.StringUtil;
import com.ganjiangps.huochetou.model.SuperEntity;
import com.github.pagehelper.PageInfo;

/**
 * BaseCRUDController
 *
 * @author :liuqh
 * @date :2017/10/23 10:46
 */
public abstract class BaseCRUDController<Entity extends SuperEntity<Entity>> extends BaseController {
	/**
	 * 日志对象
	 */
	// protected Logger logger = LoggerFactory.getLogger(getClass());

	private String viewPrefix;

	protected IService<Entity> baseService;

	/**
	 * 注入baseService
	 *
	 * @param baseService
	 */
	@Autowired
	public void setBaseService(IService<Entity> baseService) {
		this.baseService = baseService;
	}

	/**
	 * 实体类型
	 */
	protected final Class<Entity> entityClass;

	@SuppressWarnings("unchecked")
	protected BaseCRUDController() {
		Type parentType = this.getClass().getGenericSuperclass();
		// 转成参数类型接口
		ParameterizedType paramterType = (ParameterizedType) parentType;
		// 得到泛型类型
		Type[] types = paramterType.getActualTypeArguments();
		// 得到传入泛型的类
		entityClass = (Class<Entity>) types[0];

		setViewPrefix(defaultViewPrefix());
	}

	/**
	 * 为泛型创建对象
	 *
	 * @return
	 */
	protected Entity newEntity() {
		try {
			return entityClass.newInstance();
		} catch (Exception e) {
			throw new IllegalStateException("can not instantiated model : " + this.entityClass, e);
		}
	}

	/**
	 * 获取Controller层RequestMapping中的路径
	 *
	 * @return
	 */
	protected String defaultViewPrefix() {
		String currentViewPrefix = "";
		RequestMapping requestMapping = AnnotationUtils.findAnnotation(getClass(), RequestMapping.class);
		if (requestMapping != null && requestMapping.value().length > 0) {
			currentViewPrefix = requestMapping.value()[0];
		}
		return currentViewPrefix;
	}

	/**
	 * 根据id调用service得到对象
	 *
	 * @param id
	 * @return
	 */
	public Entity get(Long id) {
		if (StringUtil.isNotEmpty(id)) {
			return baseService.selectById(id);
		} else {
			return newEntity();
		}
	}

	/**
	 * 当前模块 视图的前缀 默认 1、获取当前类头上的@RequestMapping中的value作为前缀
	 */
	public void setViewPrefix(String viewPrefix) {
		if (viewPrefix.startsWith("/")) {
			viewPrefix = viewPrefix.substring(1);
		}
		this.viewPrefix = viewPrefix;
	}

	public String getViewPrefix() {
		return viewPrefix;
	}

	/**
	 * 获取视图名称：prefixViewName + "/" + simpleName + suffixName
	 * admin/entity(小写)/entity(驼峰)+ suffixName(_List/_Insert/_Update/_Detail)
	 * admin/platformaccountinfo/platformAccountInfo_List
	 * 
	 * @return
	 */
	public String display(String suffixName) {
		return getViewPrefix().toLowerCase() + "/" + getSimpleName() + suffixName;
	}

	/**
	 * 获取首字母小写的实体类名 ： 比如StudentName-->studentName
	 * 
	 * @return
	 */
	protected String getSimpleName() {
		String simpleName = newEntity().getClass().getSimpleName();
		return simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1);
	}

	/**
	 * 把查询条件对象的属性值为空字符串（""）的属性赋值为null
	 * 
	 * @param entity
	 * @return
	 * @throws IllegalAccessException
	 */
	protected Entity changeNullStringToNull(Entity entity) throws IllegalAccessException {
		Field[] fs = entity.getClass().getDeclaredFields();

		for (int i = 0; i < fs.length; i++) {

			Field f = fs[i];

			f.setAccessible(true); // 设置些属性是可以访问的

			Object val = f.get(entity); // 得到此属性的值

			if ("".equals(val)) {
				f.set(entity, null);
			}
		}
		return entity;
	}

	/**
	 * list 运行之前
	 * 
	 * @param model
	 *            数据的载体(可把要传到jsp的数据放入model内)
	 * @param entity
	 *            实体类
	 * @param orderBy
	 *            按某个字段排序如："addTime desc" 如果按默认，就传空字符串""
	 * @throws IllegalAccessException
	 */

	protected void preList(Model model, Entity entity, String orderBy) throws IllegalAccessException {
		Entity afterhandleEntity = changeNullStringToNull(entity);

		String pageNum = request.getParameter("pageNum");
		String pageSize = request.getParameter("pageSize");

		Map<String, Object> map = new HashMap<>();

		initPage(map, pageNum, pageSize);

		List<Entity> list = baseService.selectList(new EntityWrapper<Entity>(afterhandleEntity));

		PageInfo pagehelper = initPagehelper(map, list);

		model.addAttribute("pagehelper", pagehelper);
		model.addAttribute("sf", sf);
		model.addAttribute(getSimpleName(), afterhandleEntity);

	}

	@RequestMapping(value = "list", method = { RequestMethod.GET, RequestMethod.POST })
	public String list(Model model, Entity entity) throws IllegalAccessException {
		preList(model, entity, "");
		return display(Constant.VIEW_LIST);

	}

	/**
	 * 根据id查看详情前
	 *
	 * @param model
	 * @param id
	 */
	protected void preDetail(Model model, Long id) {
		Entity entity = get(id);
		model.addAttribute(getSimpleName(), entity);
		model.addAttribute("sf", sf);
	}

	/**
	 * 根据id查看详情
	 *
	 * @param model
	 * @param id
	 * @return
	 */
	@RequestMapping(value = "detail/{id}", method = { RequestMethod.GET, RequestMethod.POST })
	public String view(Model model, @PathVariable("id") Long id) {
		preDetail(model, id);
		return display(Constant.VIEW_DETAIL);
	}

	/**
	 * 新增页面前
	 *
	 * @param model
	 */
	protected void preInsertView(Model model) {

	}

	/**
	 * 新增页面
	 *
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "insertView", method = { RequestMethod.GET, RequestMethod.POST })
	protected String insertView(Model model) {
		preInsertView(model);
		return display(Constant.VIEW_INSERT);

	}

	/**
	 * 新增前(子类可重写此方法做保存前对字段进行后台验证)
	 * 
	 * @param entity
	 */

	protected boolean preInsert(Entity entity, Map<String, Object> map) {
		return true;

	}

	@RequestMapping(value = "insert", method = { RequestMethod.GET, RequestMethod.POST })
	@ResponseBody
	public Map<String, Object> insert(Entity entity) {
		Map<String, Object> map = new HashMap<>();
		map.put(Result_Constant.RESULT, Result_Constant.FAIL);

		if (!preInsert(entity, map)) {
			return map;

		}

		try {
			boolean flag = baseService.insert(entity);
			if (flag) {
				map.put(Result_Constant.MSG, "添加成功");
				map.put(Result_Constant.RESULT, Result_Constant.SUCCESS);

			}

		} catch (Exception e) {
			// TODO: handle exception
		}
		return map;
	}

	/**
	 * 新增
	 *
	 * @return
	 */

	/**
	 * 更新前
	 *
	 * @param model
	 * @param id
	 */
	protected void preUpdateView(Model model, Long id) {
		Entity entity = get(id);
		// session.setAttribute("beforeEntity", entity);
		model.addAttribute(getSimpleName(), entity);
	}

	/**
	 * 编辑页面
	 *
	 * @param id
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/updateView/{id}", method = { RequestMethod.GET, RequestMethod.POST })
	public String updateView(@PathVariable("id") Long id, Model model) {
		preUpdateView(model, id);
		return display(Constant.VIEW_UPDATE);
	}

	/**
	 * 更新前(子类可重写此方法做更新前对字段进行后台验证)
	 * 
	 * @param entity
	 */
	protected boolean preUpdate(Entity entity, Map<String, Object> map) {
		return true;
	}

	/**
	 * 更新
	 *
	 * @param entity
	 * @return
	 * @throws IOException
	 * @throws IllegalAccessException
	 */
	@RequestMapping(value = "/update", method = RequestMethod.POST)
	@ResponseBody
	public Map<String, Object> update(Entity entity) {
		Map<String, Object> map = new HashMap<>();
		// AdminUser adminUser = (AdminUser)
		// session.getAttribute("userSession");
		// Entity entity2 = (Entity) session.getAttribute("beforeEntity"); //
		// 获取到修改之前的对象
		map.put(Result_Constant.RESULT, Result_Constant.FAIL);
		if (!preUpdate(entity, map)) {
			return map;
		}
		try {
			boolean flag = baseService.updateById(entity);
			if (flag) {
				// logOperationService.insert(getLogAdmin(adminUser, entity,
				// entity2, 1,
				// LogOperationConstant.BIZTYPE_UPDATE, null, getSimpleName()));
				map.put(Result_Constant.MSG, "修改成功！");
				map.put(Result_Constant.RESULT, Result_Constant.SUCCESS);
			}
		} catch (Exception e) {
			e.printStackTrace();
			map.put(Result_Constant.MSG, "修改失败!<br />原因:" + e.getMessage());
		}
		return map;
	}

	/**
	 * 删除前
	 *
	 * @param model
	 * @param id
	 */

	protected void preDeleteView(Model model, Long id) {
		Entity entity = get(id);

		model.addAttribute(getSimpleName(), entity);

	}

	/**
	 * 删除页面
	 *
	 * @param id
	 * @param model
	 * @return
	 */

	@RequestMapping(value = "/deleteView/{id}", method = { RequestMethod.GET, RequestMethod.POST })
	public String deleteView(@PathVariable("id") Long id, Model model) {
		preDeleteView(model, id);
		return display(Constant.VIEW_DELETE);
	}

	/**
	 * 删除前(子类可重写此方法做删除前的一些逻辑处理：如启用中或已被引用了就不准删除)
	 * 
	 * @param map
	 */

	protected boolean preDelete(Map<String, Object> map, Long id) {
		return true;

	}

	/**
	 * 删除
	 *
	 * @param id
	 * @return
	 */
	@RequestMapping(value = "/delete/{id}", method = { RequestMethod.POST, RequestMethod.GET })
	@ResponseBody
	public Map<String, Object> delete(@PathVariable("id") Long id) {
		Map<String, Object> map = new HashMap<>();
		// AdminUser adminUser = (AdminUser)
		// session.getAttribute("userSession");
		map.put(Result_Constant.RESULT, Result_Constant.FAIL);
		if (!preDelete(map, id)) {
			return map;
		}
		try {
			boolean flag = baseService.deleteById(id);
			// Entity entity = (Entity)
			// session.getAttribute("beforedeleteEntity"); //获取到修改之前的对象

			if (flag) {
				// logOperationService.insert(getLogAdmin(adminUser,entity,
				// null,1,LogOperationConstant.BIZTYPE_DELETE,id,getSimpleName()));
				map.put(Result_Constant.RESULT, Result_Constant.SUCCESS);
				map.put(Result_Constant.MSG, "删除成功！");
			}
		} catch (Exception e) {
			e.printStackTrace();
			map.put(Result_Constant.MSG, "删除失败!<br />原因:" + e.getMessage());
		}
		return map;
	}

	/**
	 * 启用或者停用 传入 id 和状态字段即可
	 * 
	 * @param entity
	 *            实体类
	 * @return
	 */
	@RequestMapping("startOrStop")
	@ResponseBody
	public Map<String, Object> updateStartOrStop(Entity entity) {
		Map<String, Object> map = new HashMap<>();
		map.put(Result_Constant.RESULT, Result_Constant.FAIL);
		try {
			boolean flag = baseService.updateById(entity);
			if (flag) {
				map.put(Result_Constant.MSG, "操作成功！");
				map.put(Result_Constant.RESULT, Result_Constant.SUCCESS);
			}
		} catch (Exception e) {
			e.printStackTrace();
			map.put(Result_Constant.MSG, "操作失败!<br />原因:" + e.getMessage());
		}
		return map;
	}

	/**
	 * 通过反射获取到实体类的所有属性
	 * 
	 * @param @param
	 *            entity
	 * @param @return
	 * @param @throws
	 *            IllegalArgumentException
	 * @param @throws
	 *            IllegalAccessException
	 * @return Map<String,Object>
	 * @author jiangxueyou
	 */
	private Map<String, Object> getParam(Entity entity) throws IllegalArgumentException, IllegalAccessException {

		// 得到类对象
		Class entityClass = (Class) entity.getClass();

		// 得到类中的所有属性集合
		Field[] fs = entityClass.getDeclaredFields();
		int fieldLength = fs.length;
		HashMap<String, Object> paramMap = new HashMap<>();
		for (int i = 0; i < fieldLength; i++) {
			Field f = fs[i];
			String fieldName = f.getName();
			if ("errors".equals(fieldName) || "serialVersionUID".equals(fieldName)) {
				continue;
			}

			// 设置些属性是可以访问的
			f.setAccessible(true);

			// 得到此属性的值
			Object val = f.get(entity);
			if (val instanceof Date) {

				// 把时间改为如下格式：yyyy-MM-dd hh:mm:ss
				DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
				paramMap.put(fieldName, formatter.format(val));
			} else {
				paramMap.put(fieldName, val);
			}
		}
		return paramMap;
	}

	// private StringBuilder getParam2(Entity entityForAfter, Entity
	// entityForBefore, String simpleName)
	// throws IllegalArgumentException, IllegalAccessException {
	//
	// // 得到类对象
	// Class entityClass = entityForBefore.getClass();
	//
	// // 得到类中的所有属性集合
	// Field[] fs = entityClass.getDeclaredFields();
	// int fieldLength = fs.length;
	// StringBuilder changedParam = new StringBuilder();
	// int num = 1;
	// for (int i = 0; i < fieldLength; i++) {
	// Field f = fs[i];
	// String fieldName = f.getName();
	// if ("serialVersionUID".equals(fieldName)) {
	// continue;
	// }
	//
	// // 设置些属性是可以访问的
	// f.setAccessible(true);
	//
	// // 得到此属性的修改前的值
	// Object valForBefore = f.get(entityForBefore);
	//
	// // 得到此属性的修改后的值
	// Object valForAfter = f.get(entityForAfter);
	//
	// if (valForBefore != null && valForAfter != null &&
	// !valForBefore.equals(valForAfter)) {
	// if (valForBefore instanceof Date) {
	// // 把时间改为如下格式：yyyy-MM-dd hh:mm:ss
	// DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
	// valForBefore = formatter.format(valForBefore);
	// valForAfter = formatter.format(valForAfter);
	// }
	//
	// if (simpleName != null && !simpleName.equals("")) {
	// Map<String, String> mapdata =
	// LogOperationData_Constant.BUSINESSTYPE.get(simpleName);
	// if (mapdata != null && mapdata.size() > 0) {
	// String chineseAnnotation = mapdata.get(fieldName);
	// if (chineseAnnotation != null) {
	// changedParam
	// .append(num + ":把" + chineseAnnotation + "的值从<font color='blue'>" +
	// valForBefore
	// + "</font>----改为----<font color='blue'>" + valForAfter + "</font>")
	// .append("\r\n");
	// num++;
	// }
	// }
	// }
	// }
	//
	// }
	// return changedParam;
}
